// 给定正整数数组 A，A[i] 表示第 i 个观光景点的评分，并且两个景点 i 和 j 之间的距离为 j - i。

// 一对景点（i < j）组成的观光组合的得分为（A[i] + A[j] + i - j）：景点的评分之和减去它们两者之间的距离。

// 返回一对观光景点能取得的最高分。

//  

// 示例：

// 输入：[8,1,5,2,6]
// 输出：11
// 解释：i = 0, j = 2, A[i] + A[j] + i - j = 8 + 5 + 0 - 2 = 11
//  

// 提示：

// 2 <= A.length <= 50000
// 1 <= A[i] <= 1000

#include <vector>

using namespace std;

// 暴力搜索，超时
class Solution {
public:
    int maxScoreSightseeingPair(vector<int>& A) {
        int n = A.size();
        int res{0};
        for (int i{0}; i < n; ++i) {
            for (int j{i+1}; j < n; ++j) {
                res = max(res, A[i] + A[j] + i - j);
            }
        }
        return res;
    }
};


// 贪心算法
// 回过头来看得分公式，可以将其拆分成 A[i]+i 和 A[j]−j 两部分，这样对于统计景点 j 答案的时候，由于 A[j]−j 是固定不变的，
// 因此最大化 A[i]+i + A[j]−j 的值其实就等价于求 [0,j−1] 中 A[i]+i 的最大值 mx，
// 景点 j 的答案即为 mx+A[j]−j 。而 mx 的值我们只要从前往后枚举 j 的时候同时维护即可，
// 这样每次枚举景点 j 的时候，寻找使得得分最大的 i 就能从 O(n) 降至 O(1) 的时间复杂度，总时间复杂度就能从 O(n^2)降至 O(n)。
class Solution {
public:
    int maxScoreSightseeingPair(vector<int>& A) {
        int n = A.size();
        int res{0};
        int left = A[0] + 0;
        for (int i{1}; i < n; ++i) {
            res = max(res, A[i] - i + left);
            left = max(left, A[i] + i);
        }
        return res;
    }
};

